package de.tum.in.msspp.graph;

import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.util.ListIterator;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import org.xmlpull.v1.XmlSerializer;

import android.graphics.BitmapFactory;
import android.util.Base64;
import android.util.Log;
import android.util.Xml;

public class GraphXMLParser extends DefaultHandler {
	
	Graph graph;
	
	Node currentNode;
	Edge currentEdge;
	String currentValue;
	
	/**
	 * Parse Graph from input
	 * @param input - input stream with graph data
	 * @return a new Graph object
	 */
	public Graph xmlToGraph(InputStream input) 
	{
		//get a factory
		SAXParserFactory spf = SAXParserFactory.newInstance();
		try {

			//get a new instance of parser
			SAXParser sp = spf.newSAXParser();

			//parse the file and also register this class for call backs
			sp.parse(input, this);

		}catch(SAXException se) {
			se.printStackTrace();
		}catch(ParserConfigurationException pce) {
			pce.printStackTrace();
		}catch (IOException ie) {
			ie.printStackTrace();
		}
		
		return graph;
	}
	
	/**
	 * Parse a Graph to XML-String
	 * @param graph
	 * @return
	 */
	public String graphToXml(Graph graph)
	{	
	    XmlSerializer serializer = Xml.newSerializer();
	    StringWriter writer = new StringWriter();
	    
	    try 
	    {
	        serializer.setOutput(writer);
	        serializer.startDocument("UTF-8", true);
	        serializer.startTag("", "graph");
	        //serializer.attribute("", "number", String.valueOf(messages.size()));
	        serializer.startTag("", "nodes");

	        ListIterator<Node> nodeIterator = graph.getNodeIterator();
	        
	        //Write nodes
	        while(nodeIterator.hasNext())
	        {
	        	Node node = nodeIterator.next();
	        	serializer.startTag("", "node");
	            serializer.attribute("", "id", Integer.toString(node.getId()));
	            serializer.startTag("", "name");
	            serializer.text(node.getName());
	            serializer.endTag("", "name");
	            serializer.startTag("", "identifier");
	            serializer.text(node.getIdentifier());
	            serializer.endTag("", "identifier");
	            serializer.startTag("", "thumbnail");
	            /*
	            ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
	            
	            if(node.getThumbnail() != null)
	            {
	            	node.getThumbnail().compress(Bitmap.CompressFormat.JPEG, 100, baos); //bm is the bitmap object   
	            }
	            else
	            {
	            	//Take dummypicture
	            	node.thumbnail = null;
	            }
	            
	            //byte[] b = baos.toByteArray(); 
	            //serializer.text(Base64.encodeToString(b, Base64.DEFAULT));
	             
	             */
	            serializer.endTag("", "thumbnail");
	            serializer.endTag("", "node");
	        }
	        
	        serializer.endTag("", "nodes");
	        serializer.startTag("", "edges");
	        
	        ListIterator<Edge> edgeIterator = graph.getEdgeIterator();

	        //write edges
	        while (edgeIterator.hasNext())
	        {
	        	Edge edge = edgeIterator.next();
	        	serializer.startTag("", "edge");
	            serializer.attribute("", "id", Integer.toString(edge.getId()));
	            serializer.attribute("", "nodeId1", Integer.toString(edge.getNodeA().getId()));
	            serializer.attribute("", "nodeId2", Integer.toString(edge.getNodeB().getId()));
	            serializer.startTag("", "weight");
	            serializer.text(Double.toString(edge.getWeight()));
	            serializer.endTag("", "weight");
	            serializer.startTag("", "tags");
	            serializer.text(edge.getTags());
	            serializer.endTag("", "tags");
	        	serializer.endTag("", "edge");
	        }
	        
	        serializer.endTag("", "edges");
	        serializer.endTag("", "graph");
	        serializer.endDocument();
	        return writer.toString();
	        
	    } catch (Exception e) {
	        Log.e("XMLParser", e.getMessage());
	    } 
	    
	    return "";
	}
	
	/**
	 * Found new xml-start-tag
	 */
	public void startElement(String uri, String localName, String qName,Attributes attributes) throws SAXException 
	{
		//reset
		currentValue = "";
		if(qName.equalsIgnoreCase("graph")){
			graph = new Graph("tmp");
		}
		else if(qName.equalsIgnoreCase("node")){
			currentNode = new Node();
			currentNode.setId(Integer.parseInt(attributes.getValue("id")));
		}
		else if(qName.equalsIgnoreCase("edge")){
			currentEdge = new Edge();
			currentEdge.setId(Integer.parseInt(attributes.getValue("id")));
			currentEdge.setNodeA(graph.nodeWithId(Integer.parseInt(attributes.getValue("nodeId1"))));
			currentEdge.setNodeB(graph.nodeWithId(Integer.parseInt(attributes.getValue("nodeId2"))));
		}
	}

	/**
	 * found xml-end-tag
	 */
	public void endElement(String uri, String localName,String qName) throws SAXException 
	{
		if (qName.equalsIgnoreCase("name")) {
			currentNode.setName(currentValue);
		}else if (qName.equalsIgnoreCase("identifier")) {
			currentNode.setIdentifier(currentValue);
		}else if (qName.equalsIgnoreCase("thumbnail")) {
		    byte[] imageAsBytes = Base64.decode(currentValue.getBytes(), Base64.DEFAULT);
			currentNode.setThumbnail(BitmapFactory.decodeByteArray(imageAsBytes, 0, imageAsBytes.length));
		}else if (qName.equalsIgnoreCase("weight")) {
			currentEdge.setWeight(Double.parseDouble(currentValue));
		}else if (qName.equalsIgnoreCase("tags")) {
			currentEdge.setTags(currentValue);
		}else if (qName.equalsIgnoreCase("node")) {
			try 
			{
				graph.addNode(currentNode);
			} catch (GraphException e) {
				e.printStackTrace();
			}
		}else if (qName.equalsIgnoreCase("edge")) {
			try 
			{
				graph.addEdge(currentEdge);
			} catch (GraphException e) {
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * Found characters
	 */
	public void characters(char[] ch, int start, int length) throws SAXException 
	{
		currentValue = new String(ch,start,length);
	}
}